﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Terminal.Advanced_AEUC_settings_controls.Settings_AUX;
using CommLink;

namespace Terminal.Advanced_AEUC_settings_controls.Scripting
{
    class ScrMsgCntr
    {
        /// <summary>
        /// Event fired when a message is received
        /// </summary>
        public event CommLink.CommLink.MessageSend OnMessageReceived;
        /// <summary>
        /// Flag indicating if someone is listening for the message received event - ceise dispathing messages if no one is processing them.
        /// </summary>
        bool dispatchEnabled;
        /// <summary>
        /// Flag indicating if someone is listening for the message received event - ceise dispathing messages if no one is processing them. If there unprocessed messages when enabled is set, start dispatching them
        /// </summary>
        public bool DispatchEnabled
        {
            get
            {
                return dispatchEnabled;
            }
            set
            {
                lock (rcvdMsgData)
                {
                    dispatchEnabled = value;
                    
                    if (dispatchEnabled && rcvdMsgData.Count > 0)
                    {
                        if (OnMessageReceived != null)
                            OnMessageReceived(rcvdMsgData.Dequeue());

                        dispatchEnabled = false;
                    }
                }
            }
        }
        /// <summary>
        /// Message sending callback function
        /// </summary>
        CommLink.CommLink.MessageSend sendMessage;
        /// <summary>
        /// Queue containing all of the received messages from the communication object.
        /// </summary>
        Queue<byte[]> rcvdMsgData = new Queue<byte[]>();
        /// <summary>
        /// Reference communication object - so that the recfeive message delegate can be unregistered
        /// </summary>
        CommLink.CommLink refCommObj;
        /// <summary>
        /// Reference to the delage attached to the commnication object for incoming message processing
        /// </summary>
        CommLink.CommLink.MessageReceived msgReceiveDelegate;
        /// <summary>
        /// Flag indicating if the messaging center is initialized and tied to a communication object
        /// </summary>
        bool initialized = false;

        /// <summary>
        /// Public constructor
        /// </summary>
        /// <param name="commObj">CommLink comunication object - already opened</param>
        public ScrMsgCntr(CommLink.CommLink commObj)
        {
            if (commObj != null)
            {
                refCommObj = commObj;
                sendMessage = new CommLink.CommLink.MessageSend(commObj.msgSendData);
                msgReceiveDelegate = new CommLink.CommLink.MessageReceived(commObj_OnMessageReceived);
                commObj.OnMessageReceived += msgReceiveDelegate;
                dispatchEnabled = false;
                initialized = true;
            }
        }

        /// <summary>
        /// Stops the messaging center and destroys its underlying communication object references
        /// </summary>
        public void ScrMsgCntrStop()
        {
            if (initialized)
            {
                refCommObj.OnMessageReceived -= msgReceiveDelegate;
                FireEmptyMessageReceived();
                initialized = false;
            }
        }

        /// <summary>
        /// Close messaging center
        /// </summary>
        ~ScrMsgCntr()
        {
            ScrMsgCntrStop();
        }

        /// <summary>
        /// Resets the message dispathcer, discarding all received messages.
        /// </summary>
        public void ResetMessageDispatch()
        {
            dispatchEnabled = false;
            rcvdMsgData.Clear();
        }

        /// <summary>
        /// Handler for communication object message receive event
        /// </summary>
        /// <param name="msgData">Message data</param>
        void commObj_OnMessageReceived(byte[] msgData)
        {
            lock (rcvdMsgData)
            {
                rcvdMsgData.Enqueue(msgData);

                if (dispatchEnabled)
                {
                    if (OnMessageReceived != null)
                        OnMessageReceived(rcvdMsgData.Dequeue());

                    dispatchEnabled = false;
                }
            }
        }
        /// <summary>
        /// Forces a OnMessageReceived event with no data to be signaled - releasing any objects waiting for a message event
        /// </summary>
        public void FireEmptyMessageReceived()
        {
            if (OnMessageReceived != null)
                OnMessageReceived(null);
        }
        /// <summary>
        /// Sneds a message through the communication object
        /// </summary>
        /// <param name="msgStrm">Message data</param>
        public void SendMessage(byte[] msgStrm)
        {
            if (sendMessage != null)
                sendMessage(msgStrm);
        }

        /// <summary>
        /// Disconnect the communicaiton object
        /// </summary>
        public void commDisconnect()
        {
            if (refCommObj != null)
            {
                refCommObj.CommClose();
            }
        }
        /// <summary>
        /// Connect the communicaiton object
        /// </summary>
        public void commConnect()
        {
            if (refCommObj != null)
            {
                refCommObj.establishConnection();
            }
        }
    }
}
